package com.huiquan.vocab.utils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.huiquan.framework.utils.ArrayUtil;
import com.huiquan.framework.utils.CollectionUtil;
import com.huiquan.synonymy.dao.SynonymyWordDao;
import com.huiquan.vocab.constant.VocabConstant;
import com.huiquan.vocab.dao.VocabDyadDao;
import com.huiquan.vocab.dao.VocabDyadRemoveDao;
import com.huiquan.vocab.dao.VocabDyadStdDao;
import com.huiquan.vocab.dao.VocabElementLabelDao;
import com.huiquan.vocab.domain.HiveSymptomDyadStd;

@Service
public class SymptomStdDyadUtil2 {

	protected final Logger log = LoggerFactory.getLogger(this.getClass());

	@Autowired
	private VocabDyadDao vocabDyadDao;
	@Autowired
	private VocabDyadStdDao vocabDyadStdDao;
	@Autowired
	private VocabElementLabelDao vocabElementLabelDao;
	@Autowired
	private VocabDyadRemoveDao vocabDyadRemoveDao;
	@Autowired
	private SynonymyWordDao synonymyWordDao;

	private boolean initFlag = false;
	private boolean stdInitFlag = false;

	public void resetInitFlag() {
		initFlag = false;
		stdInitFlag = false;
	}

	/** 所有元素的同义词. */
	private Map<String, Map<String, String>> synonymMap = new HashMap<>();

	/**
	 * 根据症状分词获取对应症状标准词及二元组
	 * 
	 * @param symptomArray
	 *            症状分词
	 * @param partPattern
	 *            属性
	 * @return
	 */
	public synchronized List<HiveSymptomDyadStd> getSymptomStd(String symptomArray, String partPattern, String cnt) {

		// 初始化元素同义词
		if (!stdInitFlag) {
			initSynonym();
		}

		// 将症状分词标准化
		String[] symptom = getStdSymptomArray(symptomArray, partPattern);

		return getSymptomDyadStd(symptom[0], symptom[1], cnt);
	}

	/**
	 * 根据症状分词、分词属性和元素标准词获取症状分词标准词
	 * 
	 * @param symptomArray
	 * @return
	 */
	private String[] getStdSymptomArray(String symptomArray, String partPattern) {
		String[] symptom = new String[2];

		// 原始症状的分词和属性
		String[] properties = partPattern.substring(1).split(",");
		String[] words = symptomArray.substring(1).split(",");

		// 最终获取的标准症状和属性
		String stdSymptomArray = ",";
		String stdSymptomPartPattern = ",";

		for (int i = 0; i < properties.length; i++) {
			// 如果si或其标准词对应有o+s的标准词（二元组），则使用该标准词
			if (properties[i].equals("si")) {
				String osSymptom = si2os.get(words[i]); // 直接用该si查询
				String siStd = synonymMap.get("si").get(words[i]);
				if (osSymptom == null && siStd != null) { // 如果直接的si没有对应o+s则用该si的标准词来查询
					osSymptom = si2os.get(siStd);
				}
				if (osSymptom != null) {
					String[] osArray = osSymptom.split("" + (char) 1)[0].substring(1).split(",");
					String[] osPartPattern = osSymptom.split("" + (char) 1)[1].substring(1).split(",");
					for (int j = 0; j < osPartPattern.length; j++) {
						Map<String, String> sub = synonymMap.get(osPartPattern[j]);
						String std = "";
						if (sub != null && (std = sub.get(osArray[j])) != null) {
							stdSymptomArray += std + ",";
						} else {
							stdSymptomArray += osArray[j] + ",";
						}
						stdSymptomPartPattern += osPartPattern[j] + ",";
					}
					continue; // 该si处理完成
				}
			}

			// 如果没有特殊处理，则都是使用元素同义词的标准词来处理
			Map<String, String> sub = synonymMap.get(properties[i]);
			String std = "";
			if (sub != null && (std = sub.get(words[i])) != null) {
				stdSymptomArray += std + ",";
			} else {
				stdSymptomArray += words[i] + ",";
			}
			stdSymptomPartPattern += properties[i] + ",";
		}

		symptom[0] = stdSymptomArray;
		symptom[1] = stdSymptomPartPattern;

		return symptom;
	}

	// si标准词是o+s的数据
	Map<String, String> si2os = new HashMap<>();

	/**
	 * 将所有的同义词导出，然后维护到map中
	 */
	private void initSynonym() {

		List<Map<String, String>> si2osList = vocabDyadDao.retrieveSi2OS();
		for (Map<String, String> map : si2osList) {
			si2os.put(map.get("si").replace(",", ""), map.get("array") + (char) 1 + map.get("part_pattern"));
		}

		synonymMap = new HashMap<>();

		List<Map<String, String>> synonym = synonymyWordDao.retrieveElementSynonymByProperty("");
		List<Map<String, String>> synonymO = synonymyWordDao.retrieveElementSynonymO();

		// o的同义词特殊处理
		Map<String, String> oSub = synonymMap.get("o");
		if (oSub == null) {
			oSub = new HashMap<>();
			synonymMap.put("o", oSub);
		}
		for (Map<String, String> temp : synonymO) {
			oSub.put(temp.get("word"), temp.get("std"));
		}

		// 除了o之外的同义词统一处理
		for (Map<String, String> temp : synonym) {
			String property = temp.get("property");
			String word = temp.get("word");
			String std = temp.get("std");

			if (property.indexOf("o") < 0) {
				Map<String, String> sub = synonymMap.get(property);
				if (sub == null) {
					sub = new HashMap<>();
					synonymMap.put(property, sub);
				}

				sub.put(word, std);
			}
		}

		stdInitFlag = true;

	}

	/** 白名单. */
	private Map<String, Map<String, String>> whitelistMap = new HashMap<>();
	/** 黑名单. */
	private Map<String, List<String>> blacklistMap = new HashMap<>();
	/** p+o需合并的词，key是分词标准词，value是对应二元组标准词的标准分词合并结果. */
	private Map<String, String> poMerge = new HashMap<>();
	/** de中可修饰o的. */
	private List<String> deDecorateO = new ArrayList<>();
	/** o+oa remove原词. */
	private List<List<String>> oOaRemoveArrayList = new ArrayList<>();
	/** o+oa remove结果词. */
	private List<List<String>> oOaRemoveResultList = new ArrayList<>();
	/** o+in+s remove. */
	private Map<String, String> oInSRemoveMap = new HashMap<>();
	/** o+s核心词中需要保留多个o的. */
	private List<String> multiOCombineS = new ArrayList<>();
	/** 忽略P的规则. */
	private Map<String, String> osIgnorePStd = new HashMap<>();

	/**
	 * 初始化二元组和二元组标准词中的标准分词，由于该内容放在跑批中执行会有数据库表的冲突，所以将其在跑批之前执行，每天晚上执行一次即可
	 */
	public void initDyadStd() {
		// 初始化二元组的标准分词
		vocabDyadDao.initStdArray();

		// 初始化二元组标准词的标准分词
		vocabDyadStdDao.initStdArray();
	}

	/**
	 * <pre>
	 * 初始化全局变量中的规则
	 * 规则中所有的元素都是经过同义词转化为标准词之后的结果
	 * </pre>
	 */
	private void initRule() {

		whitelistMap = new HashMap<>();
		blacklistMap = new HashMap<>();
		poMerge = new HashMap<>();
		deDecorateO = new ArrayList<>();
		oOaRemoveArrayList = new ArrayList<>();
		oOaRemoveResultList = new ArrayList<>();
		oInSRemoveMap = new HashMap<>();
		multiOCombineS = new ArrayList<>();
		osIgnorePStd = new HashMap<>();

		// 去获取二元组对应的分词标准词及类型
		List<Map<String, String>> arrayAndStdDyad = vocabDyadDao.retrieveCheckedArrayAndStdDyad();

		Map<String, String> whitelist = null;
		for (Map<String, String> obj : arrayAndStdDyad) {
			String type = obj.get("type");
			String array = obj.get("array");
			String stdDyad = obj.get("std_dyad");
			String dyadProp = obj.get("dyad_prop");
			String flag = obj.get("flag");

			// 初始化黑白名单
			if ("1".equals(flag)) {
				// 将数据添加入黑名单中
				List<String> blacklist = blacklistMap.get(type);
				if (blacklist == null) {
					blacklist = new ArrayList<>();
					blacklistMap.put(type, blacklist);
				}
				blacklist.add(array);
			} else if ("0".equals(flag)) {
				// 将数据添加入白名单
				whitelist = whitelistMap.get(type);
				if (whitelist == null) {
					whitelist = new HashMap<>();
					whitelistMap.put(type, whitelist);
				}
				whitelist.put(array, stdDyad + "\t" + dyadProp);
			}

			// 初始化p+o需合并的词
			String mergeFlag = obj.get("merge_flag");
			if ("p+o".equals(type) && "1".equals(mergeFlag)) {
				poMerge.put(array, stdDyad.replace(",", ""));
			}
		}

		// o+oa remove初始化
		List<String> oOaRemovelist = vocabDyadRemoveDao.retrieveRemove4ExportRuleFile("o+oa");
		for (String remove : oOaRemovelist) {
			if (!remove.isEmpty() && remove.indexOf("\t") > -1) {
				// o+oa的remove用分词的第一个词语做为key分流

				List<String> array = Arrays.asList(remove.split("\t")[0].substring(1).split(","));
				List<String> result = Arrays.asList(remove.split("\t")[1].substring(1).split(","));

				oOaRemoveArrayList.add(array);
				oOaRemoveResultList.add(result);
			}
		}

		// o+in+s remove初始化
		List<String> oInSRemovelist = vocabDyadRemoveDao.retrieveRemove4ExportRuleFile("o+in+s");
		for (String remove : oInSRemovelist) {
			if (!remove.isEmpty() && remove.indexOf("\t") > -1) {
				oInSRemoveMap.put(remove.split("\t")[0], remove.split("\t")[1]);
			}
		}

		// 忽略P的规则初始化
		List<Map<String, String>> oSIgnoreP = vocabDyadDao.retrieveOSIgnoreP();
		for (Map<String, String> map : oSIgnoreP) {
			osIgnorePStd.put(map.get("o") + map.get("s"), map.get("type"));
		}

		// de中可以修饰o的列表
		deDecorateO = vocabElementLabelDao.retrieveDecorateOWord();

		// o+s核心词中需要保留多个o的
		multiOCombineS = vocabDyadDao.retrieveMultiOCombineS();

		initFlag = true;
	}

	String tempO, tempS, tempSi, tempP, tempPOMerge, tempPOInS, tempInS;
	String propertyP, propertyO, propertyPOInS, propertyInS;
	List<String> oOVocabList, oVocabList, oOPropretyList, deList, oSVocabList, oSPropertyList;
	boolean hasIn;
	String symptomStdArray = ",", symptomStdProp = ","; // 症状标准词
	String os2si = "";

	private void initTempParam() {
		tempO = "";
		tempS = "";
		tempSi = "";
		tempP = "";
		tempPOMerge = "";
		tempPOInS = "";
		tempInS = "";

		propertyP = "";
		propertyO = "";
		propertyPOInS = "";
		propertyInS = "";

		oOVocabList = new ArrayList<>();
		oVocabList = new ArrayList<>();
		oOPropretyList = new ArrayList<>();
		deList = new ArrayList<>();
		oSVocabList = new ArrayList<>();
		oSPropertyList = new ArrayList<>();

		hasIn = false;

		symptomStdArray = ",";
		symptomStdProp = ",";

		os2si = "";

	}

	/**
	 * 根据症状分词及其标准分词获取对应症状标准词及二元组
	 * 
	 * @param symptomArray
	 *            症状分词
	 * @param partPattern
	 *            属性
	 * @param stdArray
	 *            症状标准分词
	 * @return
	 */
	public List<HiveSymptomDyadStd> getSymptomDyadStd(String symptomArray, String partPattern, String cnt) {

		if (!initFlag) {
			initRule();
		}

		initTempParam();

		List<HiveSymptomDyadStd> result = new ArrayList<>();

		// 校验参数
		if (!checkParam(symptomArray, partPattern)) {
			return result;
		}

		// 如果该症状词就是一个正确的二元组，则直接返回该二元组标准词
		List<HiveSymptomDyadStd> originDyadStd = getOriginDyadStd(symptomArray, partPattern, cnt);
		if (!originDyadStd.isEmpty()) {
			return originDyadStd;
		}

		List<String> arrayList = ArrayUtil.asList(symptomArray.substring(1).split(","));
		List<String> propertyList = ArrayUtil.asList(partPattern.substring(1).split(","));

		// 忽略单双左右
		ignoreP(propertyList, arrayList);

		// 开始根据各种类型来获取二元组
		if (partPattern.indexOf("in") > -1) {

		} else if (partPattern.indexOf("si") > -1) {
			// si只会有de修饰
			checkDeSi(result, arrayList, propertyList);
		} else {
			
		}

		return result;
	}

	private void checkDeSi(List<HiveSymptomDyadStd> result, List<String> arrayList, List<String> propertyList) {
		
	}

	private List<HiveSymptomDyadStd> getOriginDyadStd(String symptomArray, String partPattern, String cnt) {
		List<HiveSymptomDyadStd> originDyadStd = new ArrayList<>();

		for (String key : whitelistMap.keySet()) {
			Map<String, String> map = whitelistMap.get(key);
			String std = map.get(symptomArray);
			if (std != null && !std.isEmpty()) {
				String dyadStdArray = std.split("\t")[0];
				String dyadStdPartPattern = std.split("\t")[1];

				HiveSymptomDyadStd dyadStd = new HiveSymptomDyadStd();
				dyadStd.setDyadStdArray(dyadStdArray);
				dyadStd.setDyadStdPartPattern(dyadStdPartPattern);
				dyadStd.setDyadArray(dyadStdArray);
				dyadStd.setDyadPartPattern(dyadStdPartPattern);
				dyadStd.setDyadType(key);
				dyadStd.setDyadFlag("0");

				dyadStd.setSymptom(dyadStdArray.replace(",", ""));
				dyadStd.setPartPattern(dyadStdPartPattern);
				dyadStd.setSymptomArray(dyadStdArray);
				dyadStd.setStdSymptom(dyadStdArray.replace(",", ""));
				dyadStd.setStdSymptomArray(dyadStdArray);
				dyadStd.setStdPartPattern(dyadStdPartPattern);
				dyadStd.setCnt(cnt);

				originDyadStd.add(dyadStd);
				break;
			}
		}
		return originDyadStd;
	}

	// 单双左右的标准词，现在默认系统里的，以后这个功能上线则按新需求来
	String danStd = "一侧";
	String shuangStd1 = "双侧";
	String shuangStd2 = "双";
	String zuoStd = "左";
	String youStd = "右";

	/**
	 * 根据维护好的数据判别该o或者o+s是否可以忽略某些p
	 * 
	 * @param propertyList
	 * @param arrayList
	 */
	private void ignoreP(List<String> propertyList, List<String> arrayList) {
		List<String> oTemp = new ArrayList<>();
		List<Integer> pIndexTemp = new ArrayList<>();

		// 是否忽略单双或左右，或者全部p忽略
		boolean danShuang = false;
		boolean zuoYou = false;
		boolean all = false;
		for (int i = 0; i < propertyList.size(); i++) {
			String property = propertyList.get(i);
			if (VocabConstant.ELEMENT_POSITION.equals(property)) {
				pIndexTemp.add(i);

			} else if (VocabConstant.ELEMENT_ORGAN.equals(property)
					|| VocabConstant.ELEMENT_ORGAN_ADITIONAL.equals(property)) {
				oTemp.add(arrayList.get(i));

			} else if (VocabConstant.ELEMENT_SYMPTOM.equals(property)) {
				for (String o : oTemp) {
					// 判断o+s是否在忽略列表中
					String os = o + arrayList.get(i);
					String type = osIgnorePStd.get(os);
					if ("1".equals(type)) {
						// 1) 左右单双方位词可以都忽略
						danShuang = true;
						zuoYou = true;
					} else if ("3".equals(type)) {
						// 3) 分单双不分左右，忽略左右
						zuoYou = true;
					} else if ("4".equals(type)) {
						// 4) 方位词都忽略
						all = true;
					}
				}
			}
		}

		if (!pIndexTemp.isEmpty()) {
			if (all) {
				for (int i = pIndexTemp.size() - 1; i >= 0; i--) {
					propertyList.remove(pIndexTemp.get(i).intValue());
					arrayList.remove(pIndexTemp.get(i).intValue());
				}
			} else {
				for (int i = pIndexTemp.size() - 1; i >= 0; i--) {
					String pTemp = arrayList.get(pIndexTemp.get(i).intValue());
					boolean isDan = danStd.equals(pTemp);
					boolean isShuang = shuangStd1.equals(pTemp) || shuangStd2.equals(pTemp);
					if (danShuang && (isDan || isShuang)) {
						propertyList.remove(pIndexTemp.get(i).intValue());
						arrayList.remove(pIndexTemp.get(i).intValue());
					}

					boolean isZuo = zuoStd.equals(pTemp);
					boolean isYou = youStd.equals(pTemp);
					if (zuoYou && (isZuo || isYou)) {
						propertyList.remove(pIndexTemp.get(i).intValue());
						arrayList.remove(pIndexTemp.get(i).intValue());
					}
				}
			}
		}
	}

	private boolean checkParam(String symptomArray, String partPattern) {

		int count1 = symptomArray.split(",").length;
		int count2 = partPattern.split(",").length;

		if (count1 == count2) {
			return true;
		}

		log.error("错误数据：" + symptomArray);
		return false;
	}
}
